tmem: expose freeable memory
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 10 Aug 2009 12:27:54 +0000 (13:27 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 10 Aug 2009 12:27:54 +0000 (13:27 +0100)
Expose tmem "freeable" memory for use by management tools.

Management tools looking for a machine with available
memory often look at free_memory to determine if there
is enough physical memory to house a new or migrating
guest.  Since tmem absorbs much or all free memory,
and since "ephemeral" tmem memory can be synchronously
freed, management tools need more data -- not only how
much memory is "free" but also how much memory is
"freeable" by tmem if tmem is told (via an already
existing tmem hypercall) to relinquish freeable memory.
This patch provides that extra piece of data (in MB).

Signed-off-by: Dan Magenheimer <dan.magenheimer@oracle.com>
tools/python/xen/lowlevel/xc/xc.c
tools/python/xen/xend/XendAPI.py
tools/python/xen/xend/XendConstants.py
tools/python/xen/xend/XendNode.py
tools/python/xen/xend/server/XMLRPCServer.py
tools/python/xen/xm/main.py
xen/common/tmem.c
xen/common/tmem_xen.c
xen/include/public/tmem.h
xen/include/xen/tmem_xen.h

index f15a5f62808e023d75b1ea0b6a14f8b71c462ae5..12895d5cbe54f0afd70f801c8a474060276b6da1 100644 (file)
@@ -1545,6 +1545,8 @@ static PyObject *pyxc_tmem_control(XcObject *self,
             return Py_BuildValue("s", buffer);
         case TMEMC_FLUSH:
             return Py_BuildValue("i", rc);
+        case TMEMC_QUERY_FREEABLE_MB:
+            return Py_BuildValue("i", rc);
         case TMEMC_THAW:
         case TMEMC_FREEZE:
         case TMEMC_DESTROY:
index 4e9e16dfbca222f56b6f86952cf10d62406d0afc..ff8cd11907c769aa27255c70d2f8cf907d0ba004 100644 (file)
@@ -934,6 +934,7 @@ class XendAPI(object):
                     ('tmem_set_weight', None),
                     ('tmem_set_cap', None),
                     ('tmem_set_compress', None),
+                    ('tmem_query_freeable_mb', None),
                     ('tmem_shared_auth', None)]
     
     host_funcs = [('get_by_name_label', None),
@@ -1134,6 +1135,14 @@ class XendAPI(object):
             return xen_api_error(e)
         return xen_api_success_void()
 
+    def host_tmem_query_freeable_mb(self, _, host_ref):
+        node = XendNode.instance()
+        try:
+            pages = node.tmem_query_freeable_mb()
+        except Exception, e:
+            return xen_api_error(e)
+        return xen_api_success(pages is None and -1 or pages)
+
     def host_tmem_shared_auth(self, _, host_ref, cli_id, uuid_str, auth):
         node = XendNode.instance()
         try:
index 22cec056524d631082406db0a6e7ce92a3710a3d..6699805a189af7c789c1db697bc958aec520826c 100644 (file)
@@ -162,4 +162,5 @@ TMEMC_LIST         = 4
 TMEMC_SET_WEIGHT   = 5
 TMEMC_SET_CAP      = 6
 TMEMC_SET_COMPRESS = 7
+TMEMC_QUERY_FREEABLE_MB = 8
 
index ac71e657c3f76f7b68ae3c2690f83d01d0779067..8a7b6cd18bb2dab7df5cdda0e75a05e54f81de38 100644 (file)
@@ -1012,6 +1012,16 @@ class XendNode:
         buf = ''
         return self.xc.tmem_control(pool_id, subop, cli_id, arg1, arg2, arg3, buf)
 
+    def tmem_query_freeable_mb(self):
+        pool_id = -1
+        cli_id = -1
+        subop = TMEMC_QUERY_FREEABLE_MB
+        arg1 = 0
+        arg2 = 0
+        arg3 = 0
+        buf = ''
+        return self.xc.tmem_control(pool_id, subop, cli_id, arg1, arg2, arg3, buf)
+
     def tmem_shared_auth(self, cli_id, uuid_str, auth):
         return self.xc.tmem_auth(cli_id, uuid_str, auth)
 
index accaabc47bc2d12e42f90df6100498b3f149170b..e7bf994646a82a40ffc20f0f9b9d89ef8d658120 100644 (file)
@@ -203,7 +203,7 @@ class XMLRPCServer:
                                'tmem_list', 'tmem_freeze', 'tmem_thaw',
                                'tmem_flush', 'tmem_destroy', 'tmem_set_weight',
                                'tmem_set_cap', 'tmem_set_compress',
-                               'tmem_shared_auth'],
+                               'tmem_query_freeable_mb', 'tmem_shared_auth'],
                              'node'),
                              (XendDmesg, ['info', 'clear'], 'node.dmesg')]:
             inst = type.instance()
index 5f3a449fee815e408661073be6c615df4a6cba7d..4654a0559a00d2e450c6d5e6e62404d0e2fbce43 100644 (file)
@@ -207,6 +207,7 @@ SUBCOMMAND_HELP = {
     'tmem-set'      :  ('[<Domain>|-a|--all] [weight=<weight>] [cap=<cap>] '
                         '[compress=<compress>]',
                         'Change tmem settings.'),
+    'tmem-freeable'  :  ('', 'Print number of freeable tmem pages.'),
     'tmem-shared-auth' :  ('[<Domain>|-a|--all] [--uuid=<uuid>] [--auth=<0|1>]', 'De/authenticate shared tmem pool.'),
 
     # security
@@ -3136,6 +3137,12 @@ def xm_tmem_set(args):
         if compress is not None:
             server.xend.node.tmem_set_compress(domid, compress)
 
+def xm_tmem_freeable_mb(args):
+    if serverType == SERVER_XEN_API:
+        print server.xenapi.host.tmem_query_freeable_mb()
+    else:
+        print server.xend.node.tmem_query_freeable_mb()
+
 def xm_tmem_shared_auth(args):
     try:
         (options, params) = getopt.gnu_getopt(args, 'au:A:', ['all','uuid=','auth='])
@@ -3258,6 +3265,7 @@ commands = {
     "tmem-destroy": xm_tmem_destroy,
     "tmem-list": xm_tmem_list,
     "tmem-set": xm_tmem_set,
+    "tmem-freeable": xm_tmem_freeable_mb,
     "tmem-shared-auth": xm_tmem_shared_auth,
     }
 
index 9df8d4d91e8f78ab8711191fcdccf59c35de3b9e..55c2aabdad0220e48ad915d47380b94e1208052c 100644 (file)
@@ -752,7 +752,7 @@ static pool_t * pool_alloc(void)
     pool_t *pool;
     int i;
 
-    if ( (pool = tmem_malloc(pool_t,NULL)) == NULL )
+    if ( (pool = tmh_alloc_infra(sizeof(pool_t),__alignof__(pool_t))) == NULL )
         return NULL;
     for (i = 0; i < OBJ_HASH_BUCKETS; i++)
         pool->obj_rb_root[i] = RB_ROOT;
@@ -780,7 +780,7 @@ static NOINLINE void pool_free(pool_t *pool)
     INVERT_SENTINEL(pool,POOL);
     pool->client = NULL;
     list_del(&pool->pool_list);
-    tmem_free(pool,sizeof(pool_t),NULL);
+    tmh_free_infra(pool);
 }
 
 /* register new_client as a user of this shared pool and return new
@@ -898,7 +898,7 @@ static void pool_flush(pool_t *pool, cli_id_t cli_id, bool_t destroy)
 
 static client_t *client_create(cli_id_t cli_id)
 {
-    client_t *client = tmem_malloc(client_t,NULL);
+    client_t *client = tmh_alloc_infra(sizeof(client_t),__alignof__(client_t));
     int i;
 
     printk("tmem: initializing tmem capability for %s=%d...",cli_id_str,cli_id);
@@ -912,7 +912,7 @@ static client_t *client_create(cli_id_t cli_id)
     {
         printk("failed... can't allocate host-dependent part of client\n");
         if ( client )
-            tmem_free(client,sizeof(client_t),NULL);
+            tmh_free_infra(client);
         return NULL;
     }
     tmh_set_client_from_id(client,cli_id);
@@ -2150,6 +2150,9 @@ static NOINLINE int do_tmem_control(struct tmem_op *op)
     case TMEMC_SET_COMPRESS:
         ret = tmemc_set_var(op->u.ctrl.cli_id,subop,op->u.ctrl.arg1);
         break;
+    case TMEMC_QUERY_FREEABLE_MB:
+        ret = tmh_freeable_mb();
+        break;
     case TMEMC_SAVE_BEGIN:
     case TMEMC_RESTORE_BEGIN:
     case TMEMC_SAVE_GET_VERSION:
index d273ab7cbeeb7731f3f3139c98ae8a442d00faa8..c11aa60d6ebda12dd9e8bff843d4509bd8363fd5 100644 (file)
@@ -26,6 +26,8 @@ boolean_param("tmem_shared_auth", opt_tmem_shared_auth);
 EXPORT int opt_tmem_lock = 0;
 integer_param("tmem_lock", opt_tmem_lock);
 
+EXPORT atomic_t freeable_page_count = ATOMIC_INIT(0);
+
 #ifdef COMPARE_COPY_PAGE_SSE2
 DECL_CYC_COUNTER(pg_copy1);
 DECL_CYC_COUNTER(pg_copy2);
index 39f7c31ebd9c6fb24bf1df77d907099f7f290ff0..0019085f0e72125193f5e4344d63d30b5881ba68 100644 (file)
@@ -55,8 +55,7 @@
 #define TMEMC_SET_WEIGHT             5
 #define TMEMC_SET_CAP                6
 #define TMEMC_SET_COMPRESS           7
-#define TMEMC_SHARED_POOL_AUTH       8
-#define TMEMC_SHARED_POOL_DEAUTH     9
+#define TMEMC_QUERY_FREEABLE_MB      8
 #define TMEMC_SAVE_BEGIN             10
 #define TMEMC_SAVE_GET_VERSION       11
 #define TMEMC_SAVE_GET_MAXPOOLS      12
index 8970327563603688bb0df70ef166b735131409d2..787e1467ff76134c6ec88d96d280b384ededd95f 100644 (file)
@@ -35,6 +35,7 @@ extern unsigned int tmh_mempool_maxalloc;
 extern struct page_list_head tmh_page_list;
 extern spinlock_t tmh_page_list_lock;
 extern unsigned long tmh_page_list_pages;
+extern atomic_t freeable_page_count;
 
 extern spinlock_t tmem_lock;
 extern spinlock_t tmem_spinlock;
@@ -102,7 +103,7 @@ static inline unsigned long tmh_avail_pages(void)
 }
 
 /*
- * Ephemeral memory allocation for persistent data 
+ * Memory allocation for persistent data 
  */
 
 static inline bool_t domain_fully_allocated(struct domain *d)
@@ -228,6 +229,8 @@ static inline struct page_info *tmh_alloc_page(void *pool, int no_heap)
     if ( pi == NULL && !no_heap )
         pi = alloc_domheap_pages(0,0,MEMF_tmem);
     ASSERT((pi == NULL) || IS_VALID_PAGE(pi));
+    if ( pi != NULL )
+        atomic_inc(&freeable_page_count);
     return pi;
 }
 
@@ -235,6 +238,7 @@ static inline void tmh_free_page(struct page_info *pi)
 {
     ASSERT(IS_VALID_PAGE(pi));
     tmh_page_list_put(pi);
+    atomic_dec(&freeable_page_count);
 }
 
 static inline unsigned int tmem_subpage_maxsize(void)
@@ -242,6 +246,26 @@ static inline unsigned int tmem_subpage_maxsize(void)
     return tmh_mempool_maxalloc;
 }
 
+static inline unsigned long tmh_freeable_mb(void)
+{
+    return (tmh_avail_pages() + _atomic_read(freeable_page_count)) >>
+            (20 - PAGE_SHIFT);
+}
+
+/*
+ * Memory allocation for "infrastructure" data
+ */
+
+static inline void *tmh_alloc_infra(size_t size, size_t align)
+{
+    return _xmalloc(size,align);
+}
+
+static inline void tmh_free_infra(void *p)
+{
+    return xfree(p);
+}
+
 #define tmh_lock_all  opt_tmem_lock
 #define tmh_flush_dups  opt_tmem_flush_dups
 #define tmh_called_from_tmem(_memflags) (_memflags & MEMF_tmem)